package uts.sdk.modules.kuxApiuseOssUploadHelper

import android.content.Context
import com.alibaba.sdk.android.oss.ClientConfiguration
import com.alibaba.sdk.android.oss.OSS
import com.alibaba.sdk.android.oss.OSSClient
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider
import com.alibaba.sdk.android.oss.model.PutObjectRequest
import com.alibaba.sdk.android.oss.ClientException
import com.alibaba.sdk.android.oss.callback.OSSProgressCallback
import com.alibaba.sdk.android.oss.model.CompleteMultipartUploadRequest
import com.alibaba.sdk.android.oss.model.CompleteMultipartUploadResult
import com.alibaba.sdk.android.oss.model.InitiateMultipartUploadRequest
import com.alibaba.sdk.android.oss.model.InitiateMultipartUploadResult
import com.alibaba.sdk.android.oss.model.UploadPartRequest
import com.alibaba.sdk.android.oss.model.UploadPartResult
import com.alibaba.sdk.android.oss.model.PartETag
import java.io.File
import java.io.RandomAccessFile
import io.dcloud.uts.console

data class OSSUploadProgress(
	val uploadId: String,
	val partETags: MutableList<PartETag>,
	val nextPartNumber: Int
)

data class OSSUploadResult(
    val isSuccess: Boolean,
    val eTag: String? = null,
    val requestId: String? = null,
    val errorMessage: String? = null,
    val exception: Exception? = null,
	val currentProgress: OSSUploadProgress? = null
)

interface OSSUploadHelperProgressListener {
	fun onProgress(currentSize: Long, totalSize: Long)
}

public class OSSUploadHelper private constructor(
    private val ossClient: OSS,
    private val bucketName: String
) {

    companion object {
        /**
         * 创建基于永久密钥的 OSSUploadHelper 实例
         */
		@Suppress("DEPRECATION")
        fun createWithPermanentKey(
            context: Context,
            accessKeyId: String,
            accessKeySecret: String,
            endpoint: String,
            bucketName: String
        ): OSSUploadHelper {
            val credentialProvider = OSSPlainTextAKSKCredentialProvider(accessKeyId, accessKeySecret)
            val config = defaultClientConfiguration()
            val ossClient = OSSClient(context, endpoint, credentialProvider, config)
            return OSSUploadHelper(ossClient, bucketName)
        }

        /**
         * 创建基于 STS 的 OSSUploadHelper 实例
         */
        fun createWithSTS(
            context: Context,
            accessKeyId: String,
            accessKeySecret: String,
            securityToken: String,
            endpoint: String,
            bucketName: String
        ): OSSUploadHelper? {
			return try {
				val credentialProvider = OSSStsTokenCredentialProvider(accessKeyId, accessKeySecret, securityToken)
				val config = defaultClientConfiguration()
				val ossClient = OSSClient(context, endpoint, credentialProvider, config)
				OSSUploadHelper(ossClient, bucketName)
			} catch (e: ClientException) {
				console.log("创建 OSSClient 时发生异常: ${e.message}")
				null
			} catch (e: Exception) {
				console.log("创建 OSSClient 时发生异常: ${e.message}")
				null
			}
        }

        /**
         * 默认的 ClientConfiguration
         */
        private fun defaultClientConfiguration(): ClientConfiguration {
            return ClientConfiguration().apply {
                connectionTimeout = 10 * 1000 // 连接超时：10秒
                socketTimeout = 10 * 1000    // 数据传输超时：10秒
                maxConcurrentRequest = 5    // 最大并发请求数
                maxErrorRetry = 2           // 失败后重试次数
                isHttpDnsEnable = true      // 启用HTTP DNS解析
            }
        }
    }

    /**
     * 上传文件到 OSS，并返回详细结果
     */
    fun uploadFile(objectKey: String, file: File, progressCallback: OSSUploadHelperProgressListener? = null): OSSUploadResult {
        if (!file.exists()) {
            return OSSUploadResult(
                isSuccess = false,
                errorMessage = "File does not exist: ${file.absolutePath}"
            )
        }
		
		if (objectKey.startsWith("/") || objectKey.startsWith("\\")) {
			return OSSUploadResult(
				isSuccess = false,
				errorMessage = "Object key cannot start with '/' or '\\'."
			)
		}

        return try {
			val putObjectRequest = PutObjectRequest(bucketName, objectKey, file.absolutePath).apply {
				this.progressCallback = OSSProgressCallback<PutObjectRequest> { _, currentSize, totalSize ->
					progressCallback?.onProgress(currentSize, totalSize)
				}
			}
            val result = ossClient.putObject(putObjectRequest)
            OSSUploadResult(
                isSuccess = true,
                eTag = result.eTag,
                requestId = result.requestId
            )
        } catch (e: Exception) {
            OSSUploadResult(
                isSuccess = false,
                errorMessage = e.message,
                exception = e
            )
        }
    }
	
	/**
	 * 分片上传，支持断点续传
	 */
	fun multipartUploadFile(
		objectKey: String,
		file: File,
		partSize: Long = 1024 * 1024 * 5, // 默认分片大学：5MB
		progressCallback: OSSUploadHelperProgressListener? = null,
		uploadProgress: OSSUploadProgress? = null
	): OSSUploadResult {
		if (!file.exists()) {
			return OSSUploadResult(
				isSuccess = false,
				errorMessage = "File does not exist: ${file.absolutePath}"
			)
		}
		
		if (objectKey.startsWith("/") || objectKey.startsWith("\\")) {
			return OSSUploadResult(
				isSuccess = false,
				errorMessage = "Object key cannot start with '/' or '\\'."
			)
		}
		
		return try {
			val uploadId = uploadProgress?.uploadId ?: initiateMultipartUpload(objectKey)
			val startPartNumber = uploadProgress?.nextPartNumber ?: 1
			val uploadedPartETags = uploadProgress?.partETags?.toMutableList() ?: mutableListOf()
			
			// 分片上传
			val newPartETags = uploadParts(
				objectKey = objectKey,
				uploadFile = file,
				partSize = partSize,
				uploadId = uploadId,
				startPartNumber = startPartNumber,
				progressCallback = progressCallback
			)
			uploadedPartETags.addAll(newPartETags)
			
			// 完成上传
			val completeResult = completeMultipartUpload(objectKey, uploadId, uploadedPartETags)
			OSSUploadResult(
				isSuccess = true,
				eTag = completeResult.eTag,
				requestId = completeResult.requestId
			)
		} catch (e: Exception) {
			// 捕获异常并记录当前上传进度
			val currentProgress = OSSUploadProgress(
				uploadId = uploadProgress?.uploadId ?: "",
				partETags = uploadProgress?.partETags ?: mutableListOf(),
				nextPartNumber = uploadProgress?.nextPartNumber ?: 1
			)
			OSSUploadResult(
				isSuccess = false,
				errorMessage = e.message,
				exception = e,
				currentProgress = currentProgress
			)
		}
	}
	
	/**
	 * 初始化分片上传
	 */
	private fun initiateMultipartUpload(objectKey: String): String {
		val initiateRequest = InitiateMultipartUploadRequest(bucketName, objectKey)
		val result = ossClient.initMultipartUpload(initiateRequest)
		return result.uploadId
	}
	
	/**
	 * 上传分片
	 */
	private fun uploadParts(
		objectKey: String,
		uploadFile: File,
		partSize: Long,
		uploadId: String,
		startPartNumber: Int,
		progressCallback: OSSUploadHelperProgressListener?
	): List<PartETag> {
		val partETags = mutableListOf<PartETag>()
		val totalSize = uploadFile.length()
		val totalParts = (totalSize / partSize).toInt() + if (totalSize % partSize > 0) 1 else 0
		RandomAccessFile(uploadFile, "r").use { raf ->
			for (partNumber in startPartNumber..totalParts) {
				val skipBytes = (partNumber - 1) * partSize
				val currentPartSize = if (partNumber == totalParts) totalSize - skipBytes else partSize
				val partContent = ByteArray(currentPartSize.toInt())
	
				raf.seek(skipBytes)
				raf.readFully(partContent)
	
				val uploadPartRequest = UploadPartRequest(bucketName, objectKey, uploadId, partNumber).apply {
					this.partContent = partContent
				}
				val uploadPartResult = ossClient.uploadPart(uploadPartRequest)
				partETags.add(PartETag(partNumber, uploadPartResult.eTag))
	
				// 更新进度回调
				val uploadedSize = minOf(partNumber * partSize, totalSize)
				progressCallback?.onProgress(uploadedSize, totalSize)
			}
		}
		return partETags
	}
	
	/**
	 * 完成分片上传
	 */
	private fun completeMultipartUpload(
		objectKey: String,
		uploadId: String,
		partETags: List<PartETag>
	): CompleteMultipartUploadResult {
		val completeRequest = CompleteMultipartUploadRequest(bucketName, objectKey, uploadId, partETags)
		return ossClient.completeMultipartUpload(completeRequest)
	}

    /**
     * 关闭 OSS 客户端
     */
    fun shutdown() {
        // Android SDK 的 OSSClient 不需要显式关闭
    }
}